package com.mysteel.monitor.servlet;

import com.mysteel.monitor.core.Handler;
import com.mysteel.monitor.core.annotation.ClassScanner;
import com.mysteel.monitor.core.annotation.DefaultClassScanner;
import com.mysteel.monitor.core.annotation.Monitor;
import com.mysteel.monitor.core.annotation.MonitorMethod;
import com.mysteel.monitor.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class ResourceServlet extends HttpServlet {

    private static  final Logger logger = LoggerFactory.getLogger(ResourceServlet.class);
    protected final String     resourcePath;
    private ClassScanner classScanner = new DefaultClassScanner();
    // 设置扫描包的位置
    protected  String scanPackage= "com.mysteel.monitor.controller";
    /** 字体文件 */
    private static final  String FONT_TYPE_FILE = ".+(.eot|.svg|.ttf|.woff|.woff2)$";

    public ResourceServlet(String resourcePath){
        this.resourcePath = resourcePath;
    }

    /**
     * url与处理器
     */
    protected final  Map<String, Handler> urlMaps = new ConcurrentHashMap<>();

    @Override
    public void init() throws ServletException {
        // 扫描并初始化
        scanClass();
    }

    /**
     * 扫描包
     */
    private void scanClass() {
        // 扫描包
       List<Class<?>>  classList = classScanner.getClassListByAnnotation(scanPackage, Monitor.class);

       if(classList != null && !classList.isEmpty()){
          for(Class cls : classList){
              Monitor monitor = (Monitor) cls.getDeclaredAnnotation(Monitor.class);
              // 公共URL
              String prefix =monitor.value();
              // 补充斜杠
              if(!prefix.endsWith("/")){
                  prefix = prefix.concat("/");
              }
              // 获取所有声明的方法
              Method[] thds = cls.getDeclaredMethods();
              if(null != thds && thds.length >0 ){
                  for(Method mtd : thds){
                      // 判断方法是否被注解修饰
                      if(mtd.isAnnotationPresent(MonitorMethod.class)){
                          MonitorMethod monitorMethod =  mtd.getDeclaredAnnotation(MonitorMethod.class);
                          String method = monitorMethod.value();
                          if(method.startsWith("/")){
                              method = method.substring(1);
                          }
                          String url = prefix.concat(method);
                          //建立URL处理关系
                          urlMaps.put(url,new Handler(cls,mtd));
                      }
                  }
              }
          }
       }
    }


    protected String getFilePath(String fileName) {
        return resourcePath + fileName;
    }

    protected void returnResourceFile(String fileName, String uri, HttpServletResponse response)
            throws ServletException,
            IOException {

        String filePath = getFilePath(fileName);

        if (filePath.contains(".html")) {
            response.setContentType("text/html; charset=utf-8");
        }
        if (fileName.endsWith(".jpg") || fileName.endsWith(".gif") || fileName.endsWith(".png")) {
            byte[] bytes = Utils.readByteArrayFromResource(filePath);
            if (bytes != null) {
                response.getOutputStream().write(bytes);
            }

            return;
        }
        // 读取字体文件
        if(fileName.matches(FONT_TYPE_FILE)){
            System.err.println(filePath);
            ServletOutputStream  outputStream = response.getOutputStream();
            InputStream fis = new BufferedInputStream(Utils.readInputStreamFromResource(filePath));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
//            fis.close();
            // 清空response
            response.reset();
            response.setContentType("application/octet-stream");
            // html 页面读取
            outputStream.write(buffer);
            outputStream.flush();
            outputStream.close();
            return;
        }
        // html 页面读取
        String text = Utils.readFromResource(filePath);
        if (fileName.endsWith(".css")) {
            response.setContentType("text/css;charset=utf-8");
        } else if (fileName.endsWith(".js")) {
            response.setContentType("text/javascript;charset=utf-8");
        }
        try {
            response.getWriter().write(text);
        }catch (NullPointerException e){
            response.sendError(HttpServletResponse.SC_FOUND);
        }
    }

    /**
     *  服务方法
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String contextPath = request.getContextPath();
        String servletPath = request.getServletPath();
        String requestURI = request.getRequestURI();
        response.setCharacterEncoding("utf-8");
        String uri = contextPath + servletPath;
        String path = requestURI.substring(contextPath.length() + servletPath.length());
        // 处理业务数据
        if (path.contains(".json")) {
            response.setContentType("application/json;charset=utf-8");
            // 处理真正的请求
            response.getWriter().print(process(path,request,response));
            return;
        }

        // find file in resources path
        returnResourceFile(path, uri, response);
    }


    protected abstract String process(String url, HttpServletRequest request, HttpServletResponse response) throws IOException;
}